import tkinter as tk
from tkinter import ttk, messagebox, filedialog, simpledialog
import pandas as pd


class Course:
    def __init__(self, course_name, credits, grade, is_repeated=False):
        self.course_name = course_name
        self.credits = credits
        self.grade = grade
        self.is_repeated = is_repeated

    def __str__(self):
        return f"课程名称：{self.course_name}, 学分：{self.credits}, 成绩：{self.grade}, 是否重修：{self.is_repeated}"


class StudentInfo:
    def __init__(self, student_id, name, department, class_name):
        self.student_id = student_id
        self.name = name
        self.department = department
        self.class_name = class_name


class AcademicData:
    def __init__(self):
        self.courses_taken = []
        self.gpa = 0.0
        self.failed_credits = 0

    def add_course(self, course):
        existing_course = next((c for c in self.courses_taken if c.course_name == course.course_name), None)
        if existing_course:
            existing_course.credits = course.credits
            existing_course.grade = course.grade
            existing_course.is_repeated = course.is_repeated
        else:
            self.courses_taken.append(course)
        self.update_gpa()
        self.update_failed_credits()

    def update_gpa(self):
        total_points = 0
        total_credits = 0
        for course in self.courses_taken:
            if course.grade >= 60:
                if course.grade >= 90:
                    points = 4.0
                elif course.grade >= 80:
                    points = 3.0
                elif course.grade >= 70:
                    points = 2.0
                elif course.grade >= 60:
                    points = 1.0
                else:
                    points = 0.0
                total_points += points * course.credits
                total_credits += course.credits
        if total_credits > 0:
            self.gpa = total_points / total_credits
        else:
            self.gpa = 0.0

    def update_failed_credits(self):
        self.failed_credits = sum(course.credits for course in self.courses_taken if course.grade < 60)


class Student:
    def __init__(self, student_info, academic_data):
        self.student_info = student_info
        self.academic_data = academic_data

    def __str__(self):
        return f"学号：{self.student_info.student_id}, 姓名：{self.student_info.name}, 所在院系：{self.student_info.department}, 班级：{self.student_info.class_name}, " \
               f"平均学分绩点：{self.academic_data.gpa:.2f}, 累计不及格课程：{self.academic_data.failed_credits}"


class StudentManager:
    def __init__(self):
        self.students = {}

    def add_student(self, student):
        self.students[student.student_info.student_id] = student
        print(f"添加学生: 学号 '{student.student_info.student_id}' (类型: {type(student.student_info.student_id)})")

    def get_student_info(self, student_id):
        print(f"查找学号: '{student_id}' (类型: {type(student_id)})")
        print(f"学生管理器中的学号列表: {[f'{key!r}' for key in self.students.keys()]}")
        return self.students.get(student_id, None)

    def add_course_to_student(self, student_id, course):
        student = self.get_student_info(student_id)
        if student:
            student.academic_data.add_course(course)

    def export_to_excel(self, file_path):
        data = []
        for student in self.students.values():
            for course in student.academic_data.courses_taken:
                data.append([
                    student.student_info.student_id,
                    student.student_info.name,
                    student.student_info.department,
                    student.student_info.class_name,
                    course.course_name,
                    course.credits,
                    course.grade,
                    "是" if course.is_repeated else "否"
                ])
        df = pd.DataFrame(data, columns=["学号", "姓名", "院系", "班级", "课程名称", "学分", "成绩", "是否重修"])
        df.to_excel(file_path, index=False)


class CourseManagerGUI:
    def __init__(self, master, student_manager, on_close_callback, data_file):
        self.master = master
        self.master.title("课程管理系统")
        self.master.geometry("600x450")
        self.student_manager = student_manager
        self.on_close_callback = on_close_callback
        self.data_file = data_file
        self.master.protocol("WM_DELETE_WINDOW", self.on_close)

        # 创建学生信息输入区域...
        # 创建分组框
        self.input_frame = ttk.LabelFrame(master, text="学生信息输入", padding=10)
        self.input_frame.grid(row=0, column=0, padx=10, pady=5, sticky="ew")

        self.query_frame = ttk.LabelFrame(master, text="查询学生信息", padding=10)
        self.query_frame.grid(row=1, column=0, padx=10, pady=5, sticky="ew")

        self.action_frame = ttk.LabelFrame(master, text="操作", padding=10)
        self.action_frame.grid(row=2, column=0, padx=10, pady=5, sticky="ew")

        self.result_frame = ttk.LabelFrame(master, text="查询结果", padding=10)
        self.result_frame.grid(row=3, column=0, padx=10, pady=5, sticky="nsew")

        # 学生信息输入区域
        self.id_label = ttk.Label(self.input_frame, text="学号:")
        self.id_label.grid(row=0, column=0, padx=5, pady=5)
        self.id_entry = ttk.Entry(self.input_frame)
        self.id_entry.grid(row=0, column=1, padx=5, pady=5)

        self.name_label = ttk.Label(self.input_frame, text="姓名:")
        self.name_label.grid(row=1, column=0, padx=5, pady=5)
        self.name_entry = ttk.Entry(self.input_frame)
        self.name_entry.grid(row=1, column=1, padx=5, pady=5)

        self.department_label = ttk.Label(self.input_frame, text="院系:")
        self.department_label.grid(row=2, column=0, padx=5, pady=5)
        self.department_entry = ttk.Entry(self.input_frame)
        self.department_entry.grid(row=2, column=1, padx=5, pady=5)

        self.class_label = ttk.Label(self.input_frame, text="班级:")
        self.class_label.grid(row=3, column=0, padx=5, pady=5)
        self.class_entry = ttk.Entry(self.input_frame)
        self.class_entry.grid(row=3, column=1, padx=5, pady=5)

        # 查询学生信息区域
        self.query_id_label = ttk.Label(self.query_frame, text="查询学号:")
        self.query_id_label.grid(row=0, column=0, padx=5, pady=5)
        self.query_id_entry = ttk.Entry(self.query_frame)
        self.query_id_entry.grid(row=0, column=1, padx=5, pady=5)

        self.query_button = ttk.Button(self.query_frame, text="查询学生", command=self.query_student)
        self.query_button.grid(row=0, column=2, padx=5, pady=5)

        # 操作按钮区域
        self.add_button = ttk.Button(self.action_frame, text="添加学生", command=self.add_student)
        self.add_button.grid(row=0, column=0, padx=5, pady=5)

        self.add_grade_button = ttk.Button(self.action_frame, text="录入学生成绩", command=self.add_grade)
        self.add_grade_button.grid(row=0, column=1, padx=5, pady=5)

        self.import_button = ttk.Button(self.action_frame, text="导入表格", command=self.import_from_file)
        self.import_button.grid(row=0, column=2, padx=5, pady=5)

        self.export_button = ttk.Button(self.action_frame, text="导出表格", command=self.export_to_file)
        self.export_button.grid(row=0, column=3, padx=5, pady=5)

        self.clear_button = ttk.Button(self.action_frame, text="清空输入", command=self.clear_entries)
        self.clear_button.grid(row=0, column=4, padx=5, pady=5)

        # 查询结果显示区域
        self.result_text = tk.Text(self.result_frame, height=10, width=70)
        self.result_text.grid(row=0, column=0, padx=5, pady=5)

        # 配置网格布局权重
        master.grid_rowconfigure(3, weight=1)
        master.grid_columnconfigure(0, weight=1)

    def save_data_to_file(self, file_path):
        self.student_manager.export_to_excel(file_path)

    def on_close(self):
        self.save_data_to_file(self.data_file)
        self.on_close_callback()
        self.master.destroy()  # 销毁副界面窗口

    def add_student(self):
        student_id = self.id_entry.get()
        name = self.name_entry.get()
        department = self.department_entry.get()
        class_name = self.class_entry.get()

        if student_id and name and department and class_name:
            student_info = StudentInfo(student_id, name, department, class_name)
            academic_data = AcademicData()
            student = Student(student_info, academic_data)
            self.student_manager.add_student(student)
            messagebox.showinfo("提示", "学生信息添加成功！")
        else:
            messagebox.showerror("错误", "请输入完整的学生信息！")

    def add_grade(self):
        student_id = self.id_entry.get()
        student = self.student_manager.get_student_info(student_id)
        if student:
            course_name = simpledialog.askstring("输入", "课程名称:")
            credits = simpledialog.askinteger("输入", "学分:")
            grade = simpledialog.askinteger("输入", "成绩:")
            is_repeated = simpledialog.askinteger("输入", "是否重修(0-否, 1-是):")
            if course_name and credits and grade is not None and is_repeated is not None:
                course = Course(course_name, credits, grade, bool(is_repeated))
                self.student_manager.add_course_to_student(student_id, course)
                messagebox.showinfo("提示", "学生成绩录入成功！")
        else:
            messagebox.showerror("错误", "未找到该学生信息！")

    def query_student(self):
        student_id = self.query_id_entry.get().strip()
        print(f"查询学号: {student_id}")  # 从查询输入框获取学号
        student = self.student_manager.get_student_info(student_id)
        if student:
            self.result_text.delete(1.0, tk.END)
            self.result_text.insert(tk.END, str(student))
            self.result_text.insert(tk.END, "\n已修课程信息：\n")
            for course in student.academic_data.courses_taken:
                self.result_text.insert(tk.END, str(course) + "\n")
        else:
            messagebox.showerror("错误", "未找到该学生信息！")

    def import_from_file(self):
        file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")])
        if file_path:
            self.import_students_from_excel(file_path)
            messagebox.showinfo("提示", "学生信息已从表格中导入成功！")

    def import_students_from_excel(self, file_path):
        df = pd.read_excel(file_path)
        for index, row in df.iterrows():
            student_id = str(row['学号'])
            name = row['姓名']
            department = row['院系']
            class_name = row['班级']
            # 检查学生是否已存在，若不存在则创建新学生信息
            if student_id not in self.student_manager.students:
                student_info = StudentInfo(student_id, name, department, class_name)
                academic_data = AcademicData()
                student = Student(student_info, academic_data)
                self.student_manager.add_student(student)
            else:
                student = self.student_manager.get_student_info(student_id)

            # 添加课程信息
            course_name = row['课程名称']
            course_credits = row['课程学分']
            course_grade = row['成绩']
            course_is_repeated = row['是否重修'] == '是'
            course = Course(course_name, course_credits, course_grade, course_is_repeated)
            self.student_manager.add_course_to_student(student_id, course)

    def export_to_file(self):
        file_path = filedialog.asksaveasfilename(defaultextension=".xlsx", filetypes=[("Excel files", "*.xlsx")])
        if file_path:
            self.student_manager.export_to_excel(file_path)
            messagebox.showinfo("提示", f"学生信息已导出到 {file_path}")

    def clear_entries(self):
        self.id_entry.delete(0, tk.END)
        self.name_entry.delete(0, tk.END)
        self.department_entry.delete(0, tk.END)
        self.class_entry.delete(0, tk.END)
        self.query_id_entry.delete(0, tk.END)
        self.result_text.delete(1.0, tk.END)


class StudentGUI:
    def __init__(self, master, data_file, student_manager):
        self.master = master
        self.master.title("学生学情管理系统")
        self.master.geometry("800x600")
        self.student_manager = student_manager
        self.data_file = data_file

        # 创建学生信息表格
        self.student_tree = ttk.Treeview(master, columns=("学号", "姓名", "院系", "班级"), show="headings")
        self.student_tree.heading("学号", text="学号")
        self.student_tree.heading("姓名", text="姓名")
        self.student_tree.heading("院系", text="院系")
        self.student_tree.heading("班级", text="班级")
        self.student_tree.column("学号", width=100, anchor='w')
        self.student_tree.column("姓名", width=100, anchor='w')
        self.student_tree.column("院系", width=150, anchor='w')
        self.student_tree.column("班级", width=100, anchor='w')
        self.student_tree.pack(pady=10, fill=tk.BOTH, expand=True)

        # 绑定选择学生事件
        self.student_tree.bind("<<TreeviewSelect>>", self.show_student_courses)

        # 创建课程信息表格
        self.course_tree = ttk.Treeview(master, columns=("课程名称", "学分", "成绩", "是否重修"), show="headings")
        self.course_tree.heading("课程名称", text="课程名称")
        self.course_tree.heading("学分", text="学分")
        self.course_tree.heading("成绩", text="成绩")
        self.course_tree.heading("是否重修", text="是否重修")
        self.course_tree.column("课程名称", width=200)
        self.course_tree.column("学分", width=50)
        self.course_tree.column("成绩", width=50)
        self.course_tree.column("是否重修", width=100)
        self.course_tree.pack(pady=10, fill=tk.BOTH, expand=True)

        # 填充学生信息表格
        for student in self.student_manager.students.values():
            self.student_tree.insert("", "end",text=student.student_info.student_id, values=(
                student.student_info.student_id, 
                student.student_info.name,
                student.student_info.department, 
                student.student_info.class_name
            ))

        # 添加“学生管理”按钮
        self.action_frame = ttk.Frame(master)
        self.action_frame.pack(pady=10)
        self.student_management_button = ttk.Button(self.action_frame, text="学生管理", command=self.open_student_management)
        self.student_management_button.pack()

    def refresh_tables(self):
        self.student_tree.delete(*self.student_tree.get_children())
        for student in self.student_manager.students.values():
            self.student_tree.insert("", "end", values=(student.student_info.student_id, student.student_info.name,
                                                       student.student_info.department, student.student_info.class_name))

    def show_student_courses(self, event):
        selected_item = self.student_tree.selection()
        if selected_item:
            item = self.student_tree.item(selected_item)
            student_id = item['text']  # 从 text 属性中获取学号
            print(f"选中的学号: {student_id}")  # 打印学号以验证
            student = self.student_manager.get_student_info(student_id)
            if student:
                self.course_tree.delete(*self.course_tree.get_children())
                for course in student.academic_data.courses_taken:
                    self.course_tree.insert("", "end", values=(course.course_name, course.credits,
                                                              course.grade, "是" if course.is_repeated else "否"))
            else:
                messagebox.showerror("错误", "未找到该学生信息！")

    def open_student_management(self):
        management_window = tk.Toplevel(self.master)
        management_app = CourseManagerGUI(management_window, self.student_manager, self.refresh_tables, self.data_file)


if __name__ == "__main__":
    data_file = "students_data.xlsx"
    student_manager = StudentManager()
    df = pd.read_excel(data_file, dtype={'学号': str})
    df['学号'] = df['学号'].str.strip()  # 去除学号的前后空格
    grouped = df.groupby('学号')
    for student_id, group in grouped:
        student_id = student_id.strip()  # 确保学号没有内部空格
        name = group['姓名'].iloc[0]
        department = group['院系'].iloc[0]
        class_name = group['班级'].iloc[0]
        student_info = StudentInfo(student_id, name, department, class_name)
        academic_data = AcademicData()
        for index, row in group.iterrows():
            course_name = row['课程名称']
            course_credits = row['学分']
            course_grade = row['成绩']
            course_is_repeated = row['是否重修'] == '是'
            course = Course(course_name, course_credits, course_grade, course_is_repeated)
            academic_data.add_course(course)
        student = Student(student_info, academic_data)
        student_manager.add_student(student)

    # 验证学号是否正确加载
    print("已加载的学号列表：", student_manager.students.keys())

    root = tk.Tk()
    app = StudentGUI(root, data_file, student_manager)
    root.mainloop()